﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Net.Sockets;

namespace HouseOfTheFuture
{
    public class GC100 : System.Net.Sockets.TcpClient, IRTransmitter
    {

        string ip_address;
        int port_num;
        int id = 0;
        bool IRTransmitter.Initialize(string ip, int port)
        {
            ip_address = ip;
            port_num = port;
            try
            {
                this.Connect(ip_address, port_num);
                return true;
            }
            catch
            {
                return false;
            }
        }
        string IRTransmitter.ip
        {
            get
            {
                return ip_address;
            }
            set
            {
                ip_address = value;
            }
        }
        int IRTransmitter.port
        {
            get
            {
                return port_num;
            }
            set
            {
                port_num = value;
            }
        }
        string IRTransmitter.SendCommand(int frequency, int emitter, int repeat, string command)
        {
            if (!this.Connected)
            {
                try
                {
                    this.Connect(ip_address, port_num);
                }
                catch(Exception ex)
                {
                    return ex.Message;
                }
            }
            byte[] bytestoSend;
            bytestoSend = System.Text.Encoding.Default.GetBytes("sendir,2:" + emitter + "," + id + "," + frequency + "," + repeat + "," + command.Replace("\r", "") + "\r");
            this.Client.Send(bytestoSend);
            bytestoSend = null;
            id++;
            return String.Empty;
        }


    }


    public class GCIRL : IRReceiver
    {
        #region API Calls
        //Thanks to Marius at http://www.csharphelp.com/board2/read.html?f=1&i=12684&t=12684 for the API calls
        [DllImport("kernel32.dll")]
        private static extern bool ClearCommError(
          int hFile,
          int lpErrors,
          object lpStat
        );
        [DllImport("kernel32.dll")]
        private static extern bool PurgeComm(
        int hFile,
        int flags
        );

        [DllImport("kernel32.dll")]
        private static extern int CreateFile(
        string lpFileName, // file name
        uint dwDesiredAccess, // access mode
        int dwShareMode, // share mode
        int lpSecurityAttributes, // SD
        int dwCreationDisposition, // how to create
        int dwFlagsAndAttributes, // file attributes
        int hTemplateFile // handle to template file
        );
        [DllImport("kernel32.dll")]
        private static extern bool GetCommState(
        int hFile, // handle to communications device
        ref DCB lpDCB // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool BuildCommDCB(
        string lpDef, // device-control string
        ref DCB lpDCB // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool GetCommTimeouts(
        int hFile, // handle to comm device
        ref COMMTIMEOUTS lpCommTimeouts // time-out values
        );
        [DllImport("kernel32.dll")]
        private static extern bool SetCommTimeouts(
        int hFile, // handle to comm device
        ref COMMTIMEOUTS lpCommTimeouts // time-out values
        );
        [DllImport("kernel32.dll")]
        private static extern bool ReadFile(
        int hFile, // handle to file
        byte[] lpBuffer, // data buffer
        int nNumberOfBytesToRead, // number of bytes to read
        ref int lpNumberOfBytesRead, // number of bytes read
        ref OVERLAPPED lpOverlapped // overlapped buffer
        );
        [DllImport("kernel32.dll")]
        private static extern bool WriteFile(
        int hFile, // handle to file
        byte[] lpBuffer, // data buffer
        int nNumberOfBytesToWrite, // number of bytes to write
        ref int lpNumberOfBytesWritten, // number of bytes written
        ref OVERLAPPED lpOverlapped // overlapped buffer
        );
        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(
        int hObject // handle to object
        );
        [DllImport("kernel32.dll")]
        private static extern uint GetLastError();

        #endregion

        #region Structures
        [StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            //taken from c struct in platform sdk
            public int DCBlength; // sizeof(DCB)
            public int BaudRate; // current baud rate
            public uint flags;
            public ushort wReserved; // not currently used
            public ushort XonLim; // transmit XON threshold
            public ushort XoffLim; // transmit XOFF threshold
            public byte ByteSize; // number of bits/byte, 4-8
            public byte Parity; // 0-4=no,odd,even,mark,space
            public byte StopBits; // 0,1,2 = 1, 1.5, 2
            public char XonChar; // Tx and Rx XON character
            public char XoffChar; // Tx and Rx XOFF character
            public char ErrorChar; // error replacement character
            public char EofChar; // end of input character
            public char EvtChar; // received event character
            public ushort wReserved1; // reserved; do not use
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;
            public int ReadTotalTimeoutMultiplier;
            public int ReadTotalTimeoutConstant;
            public int WriteTotalTimeoutMultiplier;
            public int WriteTotalTimeoutConstant;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }
        #endregion

        //win32 api constants
        private const uint GENERIC_READ = 0x80000000;
        private const uint GENERIC_WRITE = 0x40000000;
        private const int OPEN_EXISTING = 3;
        private const int INVALID_HANDLE_VALUE = -1;

        private int hComm = -1;
        int port_num;

        byte[] bytesReceived = new byte[512];

        /// <summary>
        /// Create the connection to the Serial Port
        /// </summary>
        void open()
        {
            DCB dcbCommPort = new DCB();
            COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
            hComm = CreateFile("COM" + port_num, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
            if (hComm == INVALID_HANDLE_VALUE)
            {
                 System.Windows.Forms.MessageBox.Show("Can't open COM" + port_num.ToString());
                 return;
            }
            PurgeComm(hComm, 0x0008 | 0x0004);
            // SET THE COMM TIMEOUTS.

            GetCommTimeouts(hComm, ref ctoCommPort);
            ctoCommPort.ReadTotalTimeoutConstant = 70;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            SetCommTimeouts(hComm, ref ctoCommPort);

            // SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
            GetCommState(hComm, ref dcbCommPort);
            dcbCommPort.BaudRate = 9600;
            dcbCommPort.flags = 0;
            dcbCommPort.flags |= 1;

            dcbCommPort.Parity = 0;
            dcbCommPort.ByteSize = 8;
            dcbCommPort.StopBits = 0;
            BuildCommDCB("COM" + port_num + ":baud=9600 data=8 stop = 0", ref dcbCommPort);
        }

        /// <summary>
        /// Set the COM port to use
        /// </summary>
        /// <param name="comPort">COM port the GC-IRL is connected to</param>
        bool IRReceiver.Initialize(int comPort)
        {
            port_num = comPort;
            return true;
        }
        int IRReceiver.port
        {
            get
            {
                return port_num;
            }
            set
            {
                port_num = value;
            }
        }
        /// <summary>
        /// Close the serial connection
        /// </summary>
        void Close()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hComm);
            }
        }

        /// <summary>
        /// Get any available data from the serial device
        /// </summary>
        /// <param name="NumBytes"># of bytes to return</param>
        /// <returns>Byte array containing read data</returns>
        public byte[] Read(int NumBytes)
        {
            byte[] BufBytes;
            byte[] OutBytes;
            BufBytes = new byte[NumBytes];
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesRead = 0;
                ReadFile(hComm, BufBytes, NumBytes, ref BytesRead, ref ovlCommPort);
                OutBytes = new byte[BytesRead];
                Array.Copy(BufBytes, OutBytes, BytesRead);
            }
            else
            {
                throw (new ApplicationException("Comm Port Not Open"));
            }
            return OutBytes;
        }

        /// <summary>
        /// Write data stream to the serial device
        /// </summary>
        /// <param name="WriteBytes">Byte array containing the data to write</param>
        public void Write(byte[] WriteBytes)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesWritten = 0;
                WriteFile(hComm, WriteBytes, WriteBytes.Length, ref BytesWritten, ref ovlCommPort);
            }
            else
            {
                throw (new ApplicationException("Comm Port Not Open"));
            }
        }
        string[] IRReceiver.LearnCommand()
        {
            try
            {
                open();
                string temp = "";
                while (!(temp.StartsWith("GC-IRL") && temp.Contains("\r")))
                {
                    bytesReceived = Read(512);
                    temp += System.Text.Encoding.Default.GetString(bytesReceived);
                }
                Close();
                string frequency = temp.Substring(temp.IndexOf(",") + 1, temp.IndexOf(",", temp.IndexOf(",") + 1) - temp.IndexOf(",") - 1);
                string a = "";
                string b = "";
                string c = "";
                string d = "";
                string ee = "";
                string f = "";
                string g = "";
                string h = "";
                string ii = "";
                string j = "";
                string k = "";
                string l = "";
                string m = "";
                temp = temp.Substring(temp.IndexOf(frequency) + frequency.Length + 1).Replace("\r", "");
                for (int i = 0; i < temp.Length; i++)
                {
                    if (System.Text.RegularExpressions.Regex.IsMatch(temp.Substring(i, 1), "\\d") || temp.Substring(i, 1) == ",")
                    {
                        if (a.IndexOf(",", a.IndexOf(",") + 1) == -1)
                        {
                            a += temp.Substring(i, 1);
                        }
                        else if (b.IndexOf(",", b.IndexOf(",") + 1) == -1)
                        {
                            b += temp.Substring(i, 1);
                        }
                        else if (c.IndexOf(",", c.IndexOf(",") + 1) == -1)
                        {
                            c += temp.Substring(i, 1);
                        }
                        else if (d.IndexOf(",", d.IndexOf(",") + 1) == -1)
                        {
                            d += temp.Substring(i, 1);
                        }
                        else if (ee.IndexOf(",", ee.IndexOf(",") + 1) == -1)
                        {
                            ee += temp.Substring(i, 1);
                        }
                        else if (f.IndexOf(",", f.IndexOf(",") + 1) == -1)
                        {
                            f += temp.Substring(i, 1);
                        }
                        else if (g.IndexOf(",", g.IndexOf(",") + 1) == -1)
                        {
                            g += temp.Substring(i, 1);
                        }
                        else if (h.IndexOf(",", h.IndexOf(",") + 1) == -1)
                        {
                            h += temp.Substring(i, 1);
                        }
                        else if (ii.IndexOf(",", ii.IndexOf(",") + 1) == -1)
                        {
                            ii += temp.Substring(i, 1);
                        }
                        else if (j.IndexOf(",", j.IndexOf(",") + 1) == -1)
                        {
                            j += temp.Substring(i, 1);
                        }
                        else if (k.IndexOf(",", k.IndexOf(",") + 1) == -1)
                        {
                            k += temp.Substring(i, 1);
                        }
                        else if (l.IndexOf(",", l.IndexOf(",") + 1) == -1)
                        {
                            l += temp.Substring(i, 1);
                        }
                        else if (m.IndexOf(",", m.IndexOf(",") + 1) == -1)
                        {
                            m += temp.Substring(i, 1);
                        }
                    }
                }
                if (a.EndsWith(","))
                {
                    a = a.Substring(0, a.Length - 1);
                }
                if (b.EndsWith(","))
                {
                    b = b.Substring(0, b.Length - 1);
                }
                if (c.EndsWith(","))
                {
                    c = c.Substring(0, c.Length - 1);
                }
                if (d.EndsWith(","))
                {
                    d = d.Substring(0, d.Length - 1);
                }
                if (ee.EndsWith(","))
                {
                    ee = ee.Substring(0, ee.Length - 1);
                }
                if (f.EndsWith(","))
                {
                    f = f.Substring(0, f.Length - 1);
                }
                if (g.EndsWith(","))
                {
                    g = g.Substring(0, g.Length - 1);
                }
                if (h.EndsWith(","))
                {
                    h = h.Substring(0, h.Length - 1);
                }
                if (ii.EndsWith(","))
                {
                    ii = ii.Substring(0, ii.Length - 1);
                }
                if (j.EndsWith(","))
                {
                    j = j.Substring(0, j.Length - 1);
                }
                if (k.EndsWith(","))
                {
                    k = k.Substring(0, k.Length - 1);
                }
                if (l.EndsWith(","))
                {
                    l = l.Substring(0, l.Length - 1);
                }
                if (m.EndsWith(","))
                {
                    m = m.Substring(0, m.Length - 1);
                }
                temp = temp.Replace("A", "," + a).Replace("B", "," + b).Replace("C", "," + c).Replace("D", "," + d).Replace("E", "," + ee).Replace("F", "," + f).Replace("G", "," + g).Replace("H", "," + h).Replace("I", "," + ii).Replace("J", "," + j).Replace("K", "," + k).Replace("L", "," + l).Replace("M", "," + m).Replace(",,", ",");
                string[] command = new string[1];
                command[0] = frequency;
                command[1] = temp;
                temp = null;
                frequency = null;
                return command;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Can't connect to the GC-IRL on COM" + port_num + ".\r\nPlease check the connection and try again.");
                string[] command = new string[0];
                command[0] = ex.Message;
                return command;

            }

        }
    }
}
